package cn.acac.yygh.order.service.impl;

import cn.acac.yygh.enums.OrderStatusEnum;
import cn.acac.yygh.enums.PaymentStatusEnum;
import cn.acac.yygh.exception.MyException;
import cn.acac.yygh.hosp.ScheduleFeignClient;
import cn.acac.yygh.model.order.OrderInfo;
import cn.acac.yygh.model.order.PaymentInfo;
import cn.acac.yygh.model.user.Patient;
import cn.acac.yygh.mq.MqConst;
import cn.acac.yygh.mq.RabbitMqService;
import cn.acac.yygh.order.mapper.OrderInfoMapper;
import cn.acac.yygh.order.service.OrderInfoService;
import cn.acac.yygh.order.service.PaymentService;
import cn.acac.yygh.order.service.WeixinService;
import cn.acac.yygh.order.utils.HttpRequestHelper;
import cn.acac.yygh.user.PatientFeignClient;
import cn.acac.yygh.vo.hosp.ScheduleOrderVo;
import cn.acac.yygh.vo.msm.MsmVo;
import cn.acac.yygh.vo.order.OrderMqVo;
import cn.acac.yygh.vo.order.OrderQueryVo;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.Update;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

@Service
public class OrderInfoServiceImpl
        extends ServiceImpl<OrderInfoMapper, OrderInfo>
        implements OrderInfoService {

    @Autowired
    private ScheduleFeignClient scheduleFeignClient;

    @Autowired
    private PatientFeignClient patientFeignClient;

    @Autowired
    private RabbitMqService rabbitMqService;

    @Autowired
    private WeixinService weixinService;

    @Autowired
    private PaymentService paymentService;


    public static final String POSITION = "http://localhost:9998";

    /**
     * 根据排班id和就诊人id生成订单信息
     * @param scheduleId
     * @param patientId
     * @return
     */
    @Override
    public Long submitOrder(String scheduleId, Long patientId) {
        // 1.先根据scheduleId获取挂号医生的信息
        ScheduleOrderVo scheduleOrderVo = scheduleFeignClient.findScheduleOrderById(scheduleId);
        // 2.再根据patientId获取就诊人的信息
        Patient patient = patientFeignClient.findPatient(patientId);
        // 判断是否已经过了当天的预约挂号时间
        Date stopTime = scheduleOrderVo.getStopTime();
        if(new DateTime(stopTime).isBeforeNow()){
            throw new MyException(50000,"超出当前医院的挂号时间啦！");
        }
        // 3.请求第三方医院，确认当前用户是否能挂号
        Map<String,Object> paramMap = new HashMap<>();
        paramMap.put("hoscode",scheduleOrderVo.getHoscode());
        paramMap.put("depcode",scheduleOrderVo.getDepcode());
        paramMap.put("hosScheduleId",scheduleOrderVo.getHosScheduleId());
        paramMap.put("reserveDate",scheduleOrderVo.getReserveDate());
        paramMap.put("reserveTime",scheduleOrderVo.getReserveTime());
        paramMap.put("amount",scheduleOrderVo.getAmount());
        JSONObject jsonObject = HttpRequestHelper.sendRequest(paramMap, POSITION + "/order/submitOrder");
        if(jsonObject.getInteger("code") == 200){
            // data就是返回的数据
            JSONObject data = jsonObject.getJSONObject("data");
            // 创建orderInfo对象
            OrderInfo orderInfo = new OrderInfo();
            orderInfo.setHosRecordId(data.getString("hosRecordId"));
            orderInfo.setNumber(data.getInteger("number"));
            orderInfo.setFetchTime(data.getString("fetchTime"));
            orderInfo.setFetchAddress(data.getString("fetchAddress"));
            BeanUtils.copyProperties(scheduleOrderVo,orderInfo);
            BeanUtils.copyProperties(patient,orderInfo);
            orderInfo.setPatientId(patientId);
            orderInfo.setPatientName(patient.getName());
            orderInfo.setPatientPhone(patient.getPhone());
            orderInfo.setScheduleId(scheduleId);
            orderInfo.setOrderStatus(OrderStatusEnum.UNPAID.getStatus());
            orderInfo.setOutTradeNo((System.currentTimeMillis() + new Random().nextInt(1000)) + "");
            // 3.3 在更新平台剩余的可挂号的数量
            OrderMqVo orderMqVo = new OrderMqVo();
            orderMqVo.setScheduleId(scheduleId);
            orderMqVo.setAvailableNumber(data.getIntValue("availableNumber"));
            orderMqVo.setReservedNumber(data.getIntValue("reservedNumber"));
            MsmVo msmVo = new MsmVo();
            msmVo.setPhone(patient.getPhone());
            msmVo.setTemplateCode("模板不可用！");
            orderMqVo.setMsmVo(msmVo);
            rabbitMqService.sendMessage(MqConst.EXCHANGE_DIRECT_ORDER,MqConst.ROUTING_ORDER,orderMqVo);
            // 3.4 给就诊人发送挂号成功的短信
            // 3.2 如果能挂号就讲医生信息和就诊人信息存储的mysql数据库中
            // 将数据插入到数据库中
            baseMapper.insert(orderInfo);
            // 4.返回订单的id
            return orderInfo.getId();
        }else{
            // 3.1 如果返回不能挂号，直接抛出异常
            throw new MyException(50000,"预约失败，可能挂号数已满！");
        }
    }

    /**
     * 待条件的分页查询订单接口
     * @param pageNum
     * @param pageSize
     * @param orderQueryVo
     * @return
     */
    @Override
    public Page<OrderInfo> selectOrderPage(Integer pageNum, Integer pageSize,OrderQueryVo orderQueryVo) {
        // 创建分页对象
        Page<OrderInfo> page = new Page<OrderInfo>(pageNum,pageSize);
        // 获取分页查询的条件
        String keyword = orderQueryVo.getKeyword(); // 医院名称
        Long userId = orderQueryVo.getUserId(); // 会员id
        String outTradeNo = orderQueryVo.getOutTradeNo(); //订单交易号
        Long patientId = orderQueryVo.getPatientId();   // 就诊人id
        String patientName = orderQueryVo.getPatientName();  // 就诊人名称
        String orderStatus = orderQueryVo.getOrderStatus();  //订单状态
        String reserveDate = orderQueryVo.getReserveDate();     // 预约日期
        String createTimeBegin = orderQueryVo.getCreateTimeBegin(); // 起始日期
        String createTimeEnd = orderQueryVo.getCreateTimeEnd(); // 结束日期
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper();
        if(!StringUtils.isEmpty(keyword)){
            queryWrapper.like("hosname",keyword);
        }
        if(!StringUtils.isEmpty(userId)){
            queryWrapper.eq("user_id",userId);
        }
        if(!StringUtils.isEmpty(outTradeNo)){
            queryWrapper.eq("out_trade_no",outTradeNo);
        }
        if(!StringUtils.isEmpty(patientId)){
            queryWrapper.eq("patient_id",patientId);
        }
        if(!StringUtils.isEmpty(patientName)){
            queryWrapper.like("patient_name",patientName);
        }
        if(!StringUtils.isEmpty(orderStatus)){
            queryWrapper.eq("order_status",orderStatus);
        }
        if(!StringUtils.isEmpty(reserveDate)){
            queryWrapper.eq("reserve_date",reserveDate);
        }
        if(!StringUtils.isEmpty(createTimeBegin)){
            queryWrapper.ge("create_time",createTimeBegin);
        }
        if(!StringUtils.isEmpty(createTimeEnd)){
            queryWrapper.le("create_time",createTimeEnd);
        }
        page = baseMapper.selectPage(page,queryWrapper);
        page.getRecords().stream().forEach(item -> {
            this.packetOrderInfo(item);
        });
        // 查询数据库
        return page;
    }

    /**
     * 根据订单id查询订单信息
     * @param orderId
     * @return
     */
    @Override
    public OrderInfo findOrderInfoByOrderId(Long orderId) {
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id",orderId);
        OrderInfo orderInfo = baseMapper.selectOne(queryWrapper);
        this.packetOrderInfo(orderInfo);
        return orderInfo;
    }

    /**
     * 取消愉预约的方法
     * @param orderId
     */
    @Override
    public void cancelOrder(Long orderId) {
        // 1.判断当前时间是否超过了取消预约挂号的截止时间
        OrderInfo orderInfo = baseMapper.selectById(orderId);
        // 1.1 判断时间是否已经超过
//        Date quitTime = orderInfo.getQuitTime();
//        if(new DateTime(quitTime).isBeforeNow()){
//            // 超过了截止时间，不能取消预约
//            throw new MyException(50000,"超过了取消预约的时间，取消预约失败！");
//        }
        // 2.通知第三方医院用户需要取消预约
        Map<String,Object> hospitalParamMap = new HashMap<>();
        hospitalParamMap.put("hoscode",orderInfo.getHoscode());
        hospitalParamMap.put("hosRecordId",orderInfo.getHosRecordId());
        JSONObject jsonObject = HttpRequestHelper.sendRequest(hospitalParamMap, POSITION + "/order/updateCancelStatus");
        if(jsonObject == null || jsonObject.getIntValue("code") != 200){
            // 代表第三方医院不同意取消预约
            throw new MyException(50000,"取消预约失败！");
        }
        // 3.查看用户当前是否已经支付了预约费用
        if(orderInfo.getOrderStatus().equals(OrderStatusEnum.PAID.getStatus())){
            // 用户支付了费用，进行退款操作
            Boolean flag = weixinService.refund(orderId);
        }
        // 4.更新数据库的数据
        // 更新订单表的订单状态
        orderInfo.setOrderStatus(OrderStatusEnum.CANCLE.getStatus());
        baseMapper.updateById(orderInfo);// 将支付状态修改为"已取消"
        // 更新支付表的支付状态
        UpdateWrapper<PaymentInfo> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("order_id",orderInfo.getId());
        updateWrapper.set("payment_status",PaymentStatusEnum.REFUND.getStatus());
        paymentService.update(updateWrapper);
        // 5.更新医院医生的预约数量
        // 6.给就诊人发送取消预约的短信
        OrderMqVo orderMqVo = new OrderMqVo();
        orderMqVo.setScheduleId(orderInfo.getScheduleId());
        MsmVo msmVo = new MsmVo();
        msmVo.setPhone(orderInfo.getPatientPhone());
        msmVo.setTemplateCode("xxx...");
        msmVo.setParam(null);
        orderMqVo.setMsmVo(msmVo);
        rabbitMqService.sendMessage(MqConst.EXCHANGE_DIRECT_ORDER,MqConst.ROUTING_ORDER,orderMqVo);
    }

    private void packetOrderInfo(OrderInfo orderInfo){
        orderInfo.getParam().put("orderStatusString",OrderStatusEnum.getStatusNameByStatus(orderInfo.getOrderStatus()));
    }
}
